package edu.kufpg.armatus.console;
import java.util.NavigableMap;
import java.util.NavigableSet;
import android.content.Intent;
import android.widget.Toast;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ListMultimap;
import edu.kufpg.armatus.BaseActivity;
import edu.kufpg.armatus.dialog.TerminalNotInstalledDialog;
/**
* Contains all {@link CustomCommandInfo}s and {@link Keyword}s that the console uses and allows
* {@link ConsoleActivity1} to execute commands.
*/
public class CustomCommandDispatcher {
public static final String CLIENT_COMMANDS_TAG = "Client";
private static final String CLEAR_INFO = "Hides all currently visible console entries. The entries will still be accessible from the command history.";
private static final String CONNECT_INFO = "Attempts to connect to the HERMIT server. If successful, it will load additional commands.";
private static final String EXIT_INFO = "Leaves the current console sessions, discarding any unsaved history.";
private static final String TOAST_INFO = "Displays its arguments as a pop-up on the screen.";
private static final String TERMINAL_INFO = "Opens Android Terminal Emulator, if installed.";
private static final CustomCommandInfo CLEAR = new CustomCommandInfo(CLEAR_INFO, "clear", 0, true) {
@Override
protected void run(ConsoleActivity console, String... args) {
console.clear();
}
};
private static final CustomCommandInfo CONNECT = new CustomCommandInfo(CONNECT_INFO, "connect", 1, false) {
@Override
protected void run(ConsoleActivity console, String... args) {
console.getHermitClient().connect("http://" + args[0] + ":3000");
}
};
private static final CustomCommandInfo EXIT = new CustomCommandInfo(EXIT_INFO, "exit", 0) {
@Override
protected void run(ConsoleActivity console, String... args) {
console.exit(false);
}
};
private static final CustomCommandInfo TOAST = new CustomCommandInfo(TOAST_INFO, "toast", 0, true) {
@Override
protected void run(ConsoleActivity console, String... args) {
Toast toast = null;
if (args.length == 0) {
toast = Toast.makeText(console, "No arguments!", Toast.LENGTH_SHORT);
} else {
toast = Toast.makeText(console, varargsToString(args), Toast.LENGTH_SHORT);
}
toast.show();
}
};
private static final CustomCommandInfo TERMINAL = new CustomCommandInfo(TERMINAL_INFO, "terminal", 0, true){
@Override
protected void run(ConsoleActivity console, String... args) {
String packageName = "jackpal.androidterm";
boolean installed = BaseActivity.appInstalledOrNot(console, packageName);
if (installed) {
Intent i = new Intent("jackpal.androidterm.RUN_SCRIPT");
i.addCategory(Intent.CATEGORY_DEFAULT);
i.putExtra("jackpal.androidterm.iInitialCommand", varargsToString(args));
console.startActivity(i);
} else {
TerminalNotInstalledDialog tnid = new TerminalNotInstalledDialog();
tnid.show(console.getFragmentManager(), "tnid");
}
}
};
private static final NavigableMap<String, CustomCommandInfo> CUSTOM_COMMAND_NAME_INFOS = mapCustomCommandNameInfos();
private static final NavigableSet<String> CUSTOM_COMMAND_NAMES = createCustomCommandNames();
private static final ListMultimap<String, String> CUSTOM_TAG_COMMAND_NAMES = mapCustomTagCommandNames();
private CustomCommandDispatcher() {}
static NavigableMap<String, CustomCommandInfo> getCommandNameInfos() {
return CUSTOM_COMMAND_NAME_INFOS;
}
static NavigableSet<String> getCommandSet() {
return CUSTOM_COMMAND_NAMES;
}
static ListMultimap<String, String> getTagCommandNames() {
return CUSTOM_TAG_COMMAND_NAMES;
}
/**
* Attempts to run a {@link CustomCommandInfo} on the console.
* @param console The {@link ConsoleActivity1} on which to run the {@link CustomCommandInfo}.
* @param commandName The name of the {@code Command} to run.
* @param args The parameters of the {@code Command}.
*/
public static void runCustomCommand(ConsoleActivity console, String commandName, String... args) {
CustomCommandInfo command = CUSTOM_COMMAND_NAME_INFOS.get(commandName);
if (command != null) {
runCustomCommand(console, command, args);
}
}
/**
* Attempts to run a {@link CustomCommandInfo} on the console.
* @param console The {@link ConsoleActivity1} on which to run the {@link CustomCommandInfo}.
* @param commandThe {@code Command} to run.
* @param args The parameters of the {@code Command}.
*/
private static void runCustomCommand(ConsoleActivity console, CustomCommandInfo command, String... args) {
if (command.hasLowerArgBound()) {
if (args.length < command.getArgsCount()) {
console.appendErrorResponse("ERROR: " + command.getName() +
" requires at least " + command.getArgsCount() +
(command.getArgsCount() == 1 ? " argument." :
" arguments."));
return;
}
} else if (args.length != command.getArgsCount()) {
console.appendErrorResponse("ERROR: " + command.getName() +
" requires exactly " + command.getArgsCount() +
(command.getArgsCount() == 1 ? " argument." :
" arguments."));
return;
}
command.run(console, args);
}
public static CustomCommandInfo getCustomCommand(String commandName) {
return CUSTOM_COMMAND_NAME_INFOS.get(commandName);
}
public static boolean isCustomCommand(String commandName) {
return CUSTOM_COMMAND_NAME_INFOS.containsKey(commandName);
}
/**
* Combines several strings into a single string, which each original string separated
* by a space.
* @param varargs The strings to combine into one.
* @return A new string consisting of each input string separated by a space.
*/
private static String varargsToString(String... varargs) {
StringBuilder builder = new StringBuilder();
for(String string : varargs) {
builder.append(string).append(' ');
}
return builder.toString().trim();
}
private static NavigableMap<String, CustomCommandInfo> mapCustomCommandNameInfos() {
ImmutableSortedMap.Builder<String, CustomCommandInfo> commandBuilder = ImmutableSortedMap.naturalOrder();
return commandBuilder.put(CLEAR.getName(), CLEAR)
.put(CONNECT.getName(), CONNECT)
.put(EXIT.getName(), EXIT)
.put(TERMINAL.getName(), TERMINAL)
.put(TOAST.getName(), TOAST)
.build();
}
private static NavigableSet<String> createCustomCommandNames() {
return CUSTOM_COMMAND_NAME_INFOS.navigableKeySet();
}
private static ListMultimap<String, String> mapCustomTagCommandNames() {
ImmutableListMultimap.Builder<String, String> tagMapBuilder = ImmutableListMultimap.builder();
return tagMapBuilder.putAll(CLIENT_COMMANDS_TAG, CUSTOM_COMMAND_NAME_INFOS.keySet()).build();
}
}